/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package utn.tsb.tej.comunications.client;

import com.trolltech.qt.gui.QMessageBox;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.logging.Level;
import java.util.logging.Logger;
import utn.tsb.tej.comunications.Commands;
import utn.tsb.tej.comunications.GameData;
import utn.tsb.tej.comunications.Preferences;
import utn.tsb.tej.comunications.RequestResult;
import utn.tsb.tej.comunications.server.RoomGame;
import utn.tsb.tej.world_logic.Color;
import utn.tsb.tej.world_logic.Player;
import csm.uttils.generics.Roster;

/**
 *
 * @author Carlos S. Moreno <CarlosS.Moreno@gmail.com>
 */
public class ClientRequests {

    private Socket socket;
    private String address;
    private InputStream iStream;
    private ObjectInputStream objectInput;
    private OutputStream oStream;
    private ObjectOutputStream objectOutput;

    public ClientRequests(String address) {
        this.address = address;
    }

    /**
     * Check if the IP given in the constructor is reachable and if there is
     * any T.E.J. server listening on the configured port.
     * Also, if there is a server listening, it send a request asking for the
     * room game information.
     * @return A text with the result of the request.
     */
    public RequestResult requestGameData() {
        RequestResult result;
        try {
            //We check if there is anything listening at the configured port
            if (isIPReachable(address)) {
                //If there is something listening
                System.out.println("Server Detected");
                //Conecction with the server
                prepareConnection();

                GameData gameData = checkServerGameData();

                if (null != gameData) {
                    result = new RequestResult("Room Game Detected",
                            "Room Name: " + gameData.getRoomName()
                            + "\nPlayers: " + gameData.getPlayersCount(),
                            true, QMessageBox.Icon.Information);
                } else {
                    result = new RequestResult("No T.E.J. Server Detected",
                            "There was a problem while getting the\n"
                            + "room game information. Try again later.",
                            false,
                            QMessageBox.Icon.Information);
                }


            } else {
                //If there is nothing listening
                System.out.println("No T.E.J. Server Detected at " + address
                        + ":" + Preferences.getPort());
                result = new RequestResult("No T.E.J. Server Detected",
                        "There is no T.E.J. Server listening at " + Preferences.getPort()
                        + " on " + address, false, QMessageBox.Icon.Warning);
            }
        } catch (UnknownHostException ex) {
            ex.printStackTrace();
            result = new RequestResult("No T.E.J. Server Detected",
                    "Host " + address + " unreachable", false, QMessageBox.Icon.Warning);
        } catch (IOException ex) {
            ex.printStackTrace();
            result = new RequestResult("No T.E.J. Server Detected",
                    "There was a connection problem.", false, QMessageBox.Icon.Warning);
        } finally {
            if (socket.isConnected()) {
                try {
                    closeConnection();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }

        return result;
    }

    public RequestResult requestJoinGame() {
        RequestResult result = new RequestResult("", "", false);
        try {
            //We check if there is anything listening at the configured port
            if (isIPReachable(address)) {
                //If there is something listening
                System.out.println("Server Detected");
                //Conecction with the server
                prepareConnection();

                //Ask for joining the Room Game
                objectOutput.writeInt(Commands.JOINGAME);
                objectOutput.flush();

                //The server response if there is any empty place on the room
                if (objectInput.readBoolean()) {
                    //If there is a place in the Room
                    //The server will ask for the nickname
                    objectOutput.writeUTF(Preferences.getNickname());
                    objectOutput.flush();
                    //Creates a new Player

                    //And the server will send a color.
                    Color color = (Color) objectInput.readObject();
                    Player player = new Player();
                    player.setNickName(Preferences.getNickname());
                    player.setColor(color);

                    RoomGame.setInstance((RoomGame) objectInput.readObject());

                    result = new RequestResult("Join Game", "Welcome to"
                            + color.toString(), true, QMessageBox.Icon.Information);
                    result.setRequestObject(player);
                } else {
                    result = new RequestResult("Join Game", "Sorry.\nThere are no more empty places.",
                            false, QMessageBox.Icon.Warning);
                }
            }
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
            result = new RequestResult("No T.E.J. Server Detected",
                    "There was a problem while trying to contact with the Server.", false, QMessageBox.Icon.Warning);
        } catch (UnknownHostException ex) {
            ex.printStackTrace();
            result = new RequestResult("No T.E.J. Server Detected",
                    "Host " + address + " unreachable", false, QMessageBox.Icon.Warning);
        } catch (IOException ex) {
            ex.printStackTrace();
            result = new RequestResult("No T.E.J. Server Detected",
                    "There was a connection problem.", false, QMessageBox.Icon.Warning);
        } finally {
            if (socket.isConnected()) {
                try {
                    closeConnection();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }

        return result;
    }

    public RequestResult requestRoomGameUpdate() {
        RequestResult result = new RequestResult("", "", false);
        try {
            //We check if there is anything listening at the configured port
            if (isIPReachable(address)) {
                //If there is something listening
                System.out.println("Server Detected");
                //Conecction with the server
                prepareConnection();

                //Ask for the Room Game Data
                objectOutput.writeInt(Commands.GET_ROOMGAME_UPDATE);
                objectOutput.flush();

                //The server response if it is in condition to send the data
                if (objectInput.readInt() == Commands.ACCEPT) {
                    //If the server accept the request, it sends the Room Game

                    RoomGame.setInstance((RoomGame) objectInput.readObject());

                    result = new RequestResult("Room Game Updated",
                            "Room Game successfully recived.", true,
                            QMessageBox.Icon.Information);
                } else {
                    result = new RequestResult("No T.E.J. Server Detected",
                            "The was a problem while joining the Room Game.\nTry to join again.",
                            false, QMessageBox.Icon.Warning);
                }
            }
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
            result = new RequestResult("No T.E.J. Server Detected",
                    "There was a problem while trying to contact with the Server.", false, QMessageBox.Icon.Warning);
        } catch (UnknownHostException ex) {
            ex.printStackTrace();
            result = new RequestResult("No T.E.J. Server Detected",
                    "Host " + address + " unreachable", false, QMessageBox.Icon.Warning);
        } catch (IOException ex) {
            ex.printStackTrace();
            result = new RequestResult("No T.E.J. Server Detected",
                    "There was a connection problem.", false, QMessageBox.Icon.Warning);
        } finally {
            if (socket.isConnected()) {
                try {
                    closeConnection();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }

        return result;
    }

    public RequestResult requestUpdatePlayer(Player player) {
        RequestResult result = new RequestResult("", "", false);
        try {
            //We check if there is anything listening at the configured port
            if (isIPReachable(address)) {
                //If there is something listening
                System.out.println("Server Detected");
                //Conecction with the server
                prepareConnection();

                //Tells the server that a player data update is going to be send
                objectOutput.writeInt(Commands.PLAYER_UPDATE);
                //and send the player
                objectOutput.writeObject(player);
                objectOutput.flush();

                if (objectInput.readBoolean()) {
                    //If the data is valid
                    if (objectInput.readBoolean()) {
                        //if the color change was successfull
                        result = new RequestResult("Player Updated",
                                "Player successfully sended.", true,
                                QMessageBox.Icon.Information);
                    } else {
                        player.setColor((Color) objectInput.readObject());
                        result = new RequestResult("Player Updated",
                                "The Player's color couldn't be changed.", false,
                                QMessageBox.Icon.Warning);
                    }
                } else {
                    result = new RequestResult("Player's Data Invalid",
                            "There was a problem with the player's data sended.\nTry to join again.",
                            false, QMessageBox.Icon.Warning);
                    result.setRequestObject((Color) objectInput.readObject());
                }
            }
        } catch (ClassNotFoundException ex) {
            Logger.getLogger(ClientRequests.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnknownHostException ex) {
            ex.printStackTrace();
            result = new RequestResult("No T.E.J. Server Detected",
                    "Host " + address + " unreachable", false, QMessageBox.Icon.Warning);
        } catch (IOException ex) {
            ex.printStackTrace();
            result = new RequestResult("No T.E.J. Server Detected",
                    "There was a connection problem.", false, QMessageBox.Icon.Warning);
        } finally {
            if (socket.isConnected()) {
                try {
                    closeConnection();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        }

        return result;
    }

    private void prepareConnection() throws IOException {
        socket = new Socket(address, Preferences.getPort());
        prepareOutputStreams();
        prepareInputStreams();
    }

    private void closeConnection() throws IOException {
        objectOutput.close();
        objectInput.close();
        socket.close();
    }

    private boolean isIPReachable(String address) throws UnknownHostException, IOException {
        return InetAddress.getByName(address).isReachable(3000);
    }

    private GameData checkServerGameData() throws IOException {
        //Ask for the GameData
        objectOutput.writeInt(Commands.GAMEDATA);
        objectOutput.flush();
        try {
            return (GameData) objectInput.readObject();
        } catch (ClassNotFoundException ex) {
            ex.printStackTrace();
            return null;
        }
    }

    private void prepareInputStreams() throws IOException {
        //Prepare the Input streams
        iStream = socket.getInputStream(); //Gets de conection intput stream
        objectInput = new ObjectInputStream(iStream); //Creates the Objects stream
    }

    private void prepareOutputStreams() throws IOException {
        //Prepeare the Output streams
        oStream = socket.getOutputStream(); //Gets the connection output stream
        objectOutput = new ObjectOutputStream(oStream); //Creates the Objects stream
        objectOutput.flush();
    }

    public void run() {
        try {
            socket = new Socket(address, Preferences.getPort());



        } catch (UnknownHostException ex) {
            Logger.getLogger(ThreadJoiningGame.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(ThreadJoiningGame.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
}
